package com.xqboss.apps.service.dmg;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.constant.Config;
import com.xqboss.apps.constant.LockKey;
import com.xqboss.apps.domain.dmg.DmgOrderRecord;
import com.xqboss.apps.domain.user.SysUserWallet;
import com.xqboss.apps.dto.damaigou.DeductUserIntegralDto;
import com.xqboss.apps.dto.damaigou.FallbackUserIntegralDto;
import com.xqboss.apps.dto.damaigou.QueryDeductRecordDto;
import com.xqboss.apps.dto.damaigou.QueryUserIntegralDto;
import com.xqboss.apps.enums.dmg.DmgIntegralStatusEnum;
import com.xqboss.apps.enums.user.UserWalletEnum;
import com.xqboss.apps.enums.user.WalletChangeTypeEnum;
import com.xqboss.apps.mapper.dmg.DmgOrderRecordMapper;
import com.xqboss.apps.service.user.SysUserWalletService;
import com.xqboss.common.constant.HttpStatus;
import com.xqboss.common.core.redis.lock.LockObject;
import com.xqboss.common.core.redis.lock.LockValue;
import com.xqboss.common.core.redis.lock.RedisLock;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.StringUtils;
import com.xqboss.common.utils.ip.IpUtils;
import com.xqboss.system.service.ISysConfigService;
import com.xqboss.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author Trent
 * @date 2023/9/6
 */
@Service
@Slf4j
public class DmgOrderRecordService extends ServiceImpl<DmgOrderRecordMapper, DmgOrderRecord> {

    @Autowired
    private SysUserWalletService userWalletService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysConfigService sysConfigService;


    /**
     * 扣除用户积分
     *
     * @param userId
     * @param dto
     * @return
     */
    @RedisLock(lockKey = LockKey.LOCK_DMG_ORDER)
    public DmgOrderRecord deductIntegral(@LockValue Long userId, DeductUserIntegralDto dto) {
        UserWalletEnum walletEnum = UserWalletEnum.parseByCode(dto.getIntegralCode());
        if (walletEnum == null) {
            throw new ServiceException("积分类型错误", HttpStatus.Integral_TYPE_ERROR);
        }
        // 查询用户订单扣除记录
        long count = count(new LambdaQueryWrapper<DmgOrderRecord>()
                .eq(DmgOrderRecord::getOrderId, dto.getOrderId()));
        if (count > 0) {
            throw new ServiceException("重复扣除订单", 20003);
        }
        DmgOrderRecord record = new DmgOrderRecord();
        record.setId(IdUtil.getSnowflakeNextId());
        record.setUserId(userId);
        record.setOrderId(dto.getOrderId());
        record.setAmount(dto.getAmount());
        record.setIntegralCode(dto.getIntegralCode());
        record.setStatus(DmgIntegralStatusEnum.DEDUCT);
        record.setWalletType(walletEnum);
        userWalletService.reduce(userId, walletEnum, record.getAmount(), WalletChangeTypeEnum.SHP_DEDUCT, record.getId(), "商城抵扣");
        boolean save = save(record);
        if (!save) {
            throw new ServiceException("操作失败！");
        }
        return record;
    }

    /**
     * 回退用户扣除积分
     *
     * @param dto
     * @return
     */
    @RedisLock(lockKey = LockKey.LOCK_DMG_ORDER)
    public DmgOrderRecord fallbackIntegral(@LockObject(valueFields = {"orderId", "recordId"}) FallbackUserIntegralDto dto) {
        DmgOrderRecord record;
        if (StringUtils.isNotEmpty(dto.getRecordId())) {
            record = getById(dto.getRecordId());
        } else {
            record = getOne(new LambdaQueryWrapper<DmgOrderRecord>()
                    .eq(DmgOrderRecord::getOrderId, dto.getOrderId()));
        }
        if (Objects.isNull(record)) {
            throw new ServiceException("扣除记录不存在", HttpStatus.NOT_FOUND);
        }
        if(record.getStatus() != DmgIntegralStatusEnum.DEDUCT){
            throw new ServiceException("重复回退订单", 20003);
        }
        record.setStatus(DmgIntegralStatusEnum.REFUND);
        record.setFallbackTime(LocalDateTime.now());
        record.setFallbackReason(dto.getReason());
        boolean update = update(new LambdaUpdateWrapper<DmgOrderRecord>()
                .set(DmgOrderRecord::getStatus, DmgIntegralStatusEnum.REFUND)
                .set(DmgOrderRecord::getFallbackTime, LocalDateTime.now())
                .set(DmgOrderRecord::getFallbackReason, dto.getReason())
                .eq(DmgOrderRecord::getId, record.getId()));
        if (!update) {
            throw new ServiceException("操作失败！");
        }
        userWalletService.increase(record.getUserId(), record.getWalletType(), record.getAmount(), WalletChangeTypeEnum.SHP_FALLBACK, record.getId(), "商城退单");
        return record;
    }

    /**
     * 查询扣除记录
     *
     * @param dto
     * @return
     */
    public DmgOrderRecord queryRecord(QueryDeductRecordDto dto) {
        DmgOrderRecord record;
        if (StringUtils.isNotEmpty(dto.getRecordId())) {
            record = getById(dto.getRecordId());
        } else {
            record = getOne(new LambdaQueryWrapper<DmgOrderRecord>()
                    .eq(DmgOrderRecord::getOrderId, dto.getOrderId()));
        }
        if (Objects.isNull(record)) {
            throw new ServiceException("扣除记录不存在", HttpStatus.NOT_FOUND);
        }
        return record;
    }

    /**
     * 查询用户钱包信息
     *
     * @param dto
     * @return
     */
    public List<SysUserWallet> queryWallet(QueryUserIntegralDto dto) {
        List<String> integralCodes = dto.getIntegralCode();
        List<UserWalletEnum> walletEnumList = new ArrayList<>();
        if (Objects.nonNull(integralCodes) && !integralCodes.isEmpty()) {
            for (String integralCode : integralCodes) {
                UserWalletEnum walletEnum = UserWalletEnum.parseByCode(integralCode);
                if (Objects.isNull(walletEnum)) {
                    throw new ServiceException("积分类型[" + integralCode + "]错误", HttpStatus.Integral_TYPE_ERROR);
                }
                walletEnumList.add(walletEnum);
            }
        } else {
            walletEnumList.add(UserWalletEnum.INTEGRAL);
        }
        try {
            Long userId = Long.parseLong(dto.getUserId());
            List<SysUserWallet> walletList = new ArrayList<>();
            for (UserWalletEnum walletEnum : walletEnumList) {
                SysUserWallet wallet = userWalletService.getWallet(userId, walletEnum);
                walletList.add(wallet);
            }
            return walletList;
        } catch (Exception e) {
            throw new ServiceException("用户不存在！", HttpStatus.NOT_FOUND);
        }
    }

    /**
     * 检测白名单
     */
    public void checkWhiteList() {
        List<String> ipList = sysConfigService.getValue(Config.Sys.DaMaiGou.大麦购IP白名单);
        String ipAddr = IpUtils.getIpAddr();
        log.debug("请求IP：{}", ipAddr);
        if (ipList.stream().noneMatch(ip -> Objects.equals(ip, ipAddr))) {
            log.error("非白名单IP请求接口:{}", ipAddr);
            throw new ServiceException("暂无权限", HttpStatus.UNAUTHORIZED);
        }
    }
}
